﻿using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Text;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Mvc.Formatters;
using RJCP.IO.Ports;
using ST.Data;
using ST.ModelVM.ProtocolDefine;
using ST.ModelVM.ProtocolSimHost;
using ST.Simulator.Tasks;

namespace ST.Simulator.Trans
{
    public   class UdpTrans : AbstractTrans
    {
        public ILogger<UdpTrans> _logger;
        Socket listenSocket =null ;
         
        CancellationTokenSource cts = new CancellationTokenSource();
        CancellationToken token;
        public UdpTrans(ILogger<UdpTrans> _logger)
        {
            this._logger = _logger;
        }
        public override void Start(ProtocolSim sim)
        {
            protocolSim = sim;
            token = cts.Token;
            Task.Run(()=> StartListen());
            base.Start(sim);    
        }
        
        public override void Stop()
        {
            try
            {
                cts.Cancel();


                if (listenSocket != null)
                {
                    listenSocket.Close();
                    listenSocket = null;
                }
                 
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Stop error");
            }

            base.Stop();    
        }
 
         
        byte[] buffer = new byte[1024];
        DateTime LstOpenDt = DateTime.MinValue;
        IPEndPoint remoteEndPoint=new IPEndPoint(IPAddress.Any,0);
        bool Open()
        {
            if( (DateTime.Now- LstOpenDt).TotalSeconds < 5)
            {
                return false;
            }
            
            listenSocket =  new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            listenSocket.Bind(new IPEndPoint(IPAddress.Any, protocolSim.Port));
             
            return IsOpen();
        }
        bool IsOpen()
        {
            return listenSocket != null && listenSocket.IsBound;
        }
        public async void StartListen()
        {
            try
            {
                while (!token.IsCancellationRequested)
                {
                    try {
                        if (!IsOpen())
                        {
                            Open();
                        }
                        var r =await listenSocket.ReceiveFromAsync(buffer,   remoteEndPoint,token);
                        if (r.ReceivedBytes > 0)
                        {
                            remoteEndPoint = r.RemoteEndPoint as IPEndPoint;
                            Read(  r.ReceivedBytes);
                        }
                         
                    }
                    catch(Exception  ex2)
                    {
                        if(token.IsCancellationRequested)
                        {
                            break;
                        }
                        _logger.LogError(ex2.Message??"");
                        _logger.LogError(ex2.StackTrace??"");
                    }
                    

                }                 
            }
            catch (Exception ex1)
            {
                _logger.LogError(ex1.Message ?? "");
                _logger.LogError(ex1.StackTrace ?? "");
                throw  ;
            }
        }
        public void Read(int ReceivedBytes)
        {
            byte[] receivedData = new byte[ReceivedBytes];
            Array.Copy(buffer, receivedData, ReceivedBytes);

            if (IsModbusTcp(receivedData))
            {
                var trd = new TcpReqData(receivedData);
                var mhost = TransTask.Instance.lData.Where(a => a.ProtocolSimId == protocolSim.Id).FirstOrDefault();
                if (trd.unitId == mhost.HostId)
                {
                    if (trd.functionCode == 5 || trd.functionCode == 6 || trd.functionCode == 10)
                    {
                        listenSocket.SendTo(receivedData, remoteEndPoint);
                        TransTask.Instance.AddSimLog(protocolSim, mhost.Id, "发送", receivedData,
                           $"应答指令 {trd.functionCode}");
                         
                        return;
                    }
                    var StartAddress = trd.StartAddress;
                    var EndAddress = trd.StartAddress + trd.ReqNum;
                    var cmd = mhost.GDSJ.Where(a => a.Gnm == trd.functionCode
                    && a.StartAddress <= StartAddress
                    && a.EndAddress >= EndAddress
                    ).FirstOrDefault();
                    if (cmd != null)
                    {
                        HandeGd(listenSocket, cmd, trd, mhost, receivedData);                        
                        return;
                    }
                    var cmd2 = mhost.XHSJ.Where(a => a.Gnm == trd.functionCode
                   && a.StartAddress <= StartAddress
                   && a.EndAddress >= EndAddress
                   ).FirstOrDefault();
                    if (cmd2 != null)
                    {
                        HandeXh(listenSocket, cmd2, trd, mhost, receivedData);                         
                        return;
                    }
                }
                TransTask.Instance.AddSimLog(protocolSim, 0, "接收", receivedData, "无效数据");
            }
            else
            {
                TransTask.Instance.AddSimLog(protocolSim, 0, "接收", receivedData, "无效数据");
            }


        }

         

        private bool IsModbusTcp(byte[] data)
        {
            // Modbus TCP协议最小长度为7字节
            if (data.Length < 7) return false;

            // 事务标识符（通常为0）
            // 协议标识符（Modbus TCP固定为0）
            // 长度字段（包括单元标识符和功能码）
            // 单元标识符（通常为1）
            return true;
        }
        void HandeGd(Socket handler, ProtocolGDSJVM cmd,TcpReqData trd, ProtocolSimHostVM mhost, byte[] receivedData)
        {
            TransTask.Instance.AddSimLog(protocolSim, mhost.Id, "接收", receivedData,
                                    $"请求 {trd.StartAddress} 个数{trd.ReqNum}");
            var StartAddress = trd.StartAddress;
            var EndAddress = trd.StartAddress + trd.ReqNum;

            byte[] senddata = null;
            if (cmd.BitData)
            {

            }
            else
            {
                var index = (StartAddress - cmd.StartAddress) * 2;
                var len = trd.ReqNum * 2;
                senddata = new byte[len];
                Array.Copy(cmd.Bytes, index, senddata, 0, len);
            }
            var sendData2 = new byte[senddata.Length + 9];
            sendData2[0] = receivedData[0];
            sendData2[1] = receivedData[1];
            sendData2[2] = receivedData[2];
            sendData2[3] = receivedData[3];
            sendData2[4] = Convert.ToByte((senddata.Length + 3) / 256);
            sendData2[5] = Convert.ToByte((senddata.Length + 3) % 256);
            sendData2[6] = receivedData[6];
            sendData2[7] = receivedData[7];

            sendData2[8] = Convert.ToByte(senddata.Length);

            Array.Copy(senddata, 0, sendData2, 9, senddata.Length);

             handler.SendTo(sendData2,remoteEndPoint);
            TransTask.Instance.AddSimLog(protocolSim, mhost.Id, "发送", sendData2,
               $"应答 {trd.StartAddress} 有效数据{senddata.Length} 字节：{sendData2.Length}");
        }


        void HandeXh(Socket handler, ProtocolXHSJVM cmd, TcpReqData trd, ProtocolSimHostVM mhost, byte[] receivedData)
        {
            TransTask.Instance.AddSimLog(protocolSim, mhost.Id, "接收", receivedData,
                                    $"请求 {trd.StartAddress}个数 {trd.ReqNum}");
            var StartAddress = trd.StartAddress;
            var EndAddress = trd.StartAddress + trd.ReqNum;

            byte[] senddata = null;
            if (cmd.BitData)
            {

            }
            else
            {
                var index = (StartAddress - cmd.StartAddress) * 2;
                var len = trd.ReqNum * 2;
                senddata = new byte[len];
                Array.Copy(cmd.Bytes, index, senddata, 0, len);
            }
            var sendData2 = new byte[senddata.Length + 9];
            sendData2[0] = receivedData[0];
            sendData2[1] = receivedData[1];
            sendData2[2] = receivedData[2];
            sendData2[3] = receivedData[3];
            sendData2[4] = Convert.ToByte((senddata.Length + 3) / 256);
            sendData2[5] = Convert.ToByte((senddata.Length + 3) % 256);
            sendData2[6] = receivedData[6];
            sendData2[7] = receivedData[7];

            sendData2[8] = Convert.ToByte(senddata.Length);

            Array.Copy(senddata, 0, sendData2, 9, senddata.Length);

           
            handler.SendTo(sendData2,remoteEndPoint);
            TransTask.Instance.AddSimLog(protocolSim, mhost.Id, "发送", sendData2,
               $"应答 {trd.StartAddress} 有效数据{senddata.Length} 字节：{sendData2.Length}");

        }

    }
}
